/*
 * inference-101
 */

#ifndef __GSTREAMER_CAMERA_H__
#define __GSTREAMER_CAMERA_H__

#include "Camera.h"

#include <gst/gst.h>
#include <string>


struct _GstAppSink;
class QWaitCondition;
class QMutex;


/**
 * gstreamer CSI camera using nvcamerasrc
 */
class gstCamera : public Camera
{
public:
	static gstCamera* Create();
	virtual ~gstCamera();

	virtual bool Open();
	virtual bool Close();
	
	// Capture YUV (NV12)
	bool Capture( void** cpu, void** cuda, unsigned long timeout=ULONG_MAX );
	
	// Takes in captured YUV-NV12 CUDA image, converts to float4 RGBA (with pixel intensity 0-255)
	bool ConvertRGBA( void* input, void** output );
	
	inline uint32_t GetWidth() const	  { return mWidth; }
	inline uint32_t GetHeight() const	  { return mHeight; }
	inline uint32_t GetPixelDepth() const { return mDepth; }
	inline uint32_t GetSize() const		  { return mSize; }
	
private:
	static void onEOS(_GstAppSink* sink, void* user_data);
	static GstFlowReturn onPreroll(_GstAppSink* sink, void* user_data);
	static GstFlowReturn onBuffer(_GstAppSink* sink, void* user_data);

	gstCamera();
	
	bool init();
	bool buildLaunchStr();
	void checkMsgBus();
	void checkBuffer();
	
	_GstBus*     mBus;
	_GstAppSink* mAppSink;
	_GstElement* mPipeline;

	std::string  mLaunchStr;
	
	static const uint32_t NUM_RINGBUFFERS = 4;
	
	void* mRingbufferCPU[NUM_RINGBUFFERS];
	void* mRingbufferGPU[NUM_RINGBUFFERS];
	
	QWaitCondition* mWaitEvent;
	
	QMutex* mWaitMutex;
	QMutex* mRingMutex;
	
	uint32_t mLatestRingbuffer;
	bool     mLatestRetrieved;
	
	void* mRGBA;
};

#endif
